#include "pch.h"
#include "skyPlane.h"
#include "Scene.h"
namespace mini
{

	CSkyPlane::CSkyPlane()
	{
		mbAlwayShow = true;
	}

	CSkyPlane::~CSkyPlane()
	{
		SafeDelete(mpMeshUnits.front());
		SafeDeleteArray(mSkyPlane);
		mpMeshUnits.clear();
	}

	void CSkyPlane::updateFrame(float fDeltaTime)
	{
		auto* pCamera = dynamic_cast<CCamera*>(GEngine->getActiveCamera());
		if (nullptr != pCamera)
		{
			setPosition(pCamera->getEye());
		}
		if (0 != mpMeshUnits.size())
		{
			m_textureTranslation[0] += m_translationSpeed[0];
			m_textureTranslation[1] += m_translationSpeed[1];
			m_textureTranslation[2] += m_translationSpeed[2];
			m_textureTranslation[3] += m_translationSpeed[3];

			// Keep the values in the zero to one range.
			if (m_textureTranslation[0] > 1.0f)
			{
				m_textureTranslation[0] -= 1.0f; 
			}
			if (m_textureTranslation[1] > 1.0f) 
			{
				m_textureTranslation[1] -= 1.0f; 
			}
			if (m_textureTranslation[2] > 1.0f)
			{
				m_textureTranslation[2] -= 1.0f; 
			}
			if (m_textureTranslation[3] > 1.0f) 
			{
				m_textureTranslation[3] -= 1.0f; 
			}

			auto materialUnit = mpMeshUnits.front()->getMaterialUnit();
			materialUnit->updatePSConstBuffer("SkyCloudBuffer", &mPSParam);
		}
	}

	bool CSkyPlane::initialise(int planeSize, int texRepeat, float planeWidth, float planeTop, float planeBottom)
	{
		mSkyPlane = new SkyPlaneType[(planeSize+1) * (planeSize + 1)];
		if (!mSkyPlane)
		{
			return false;
		}

		float quadSize, radius, constant, textureDelta;
		float positionX, positionY, positionZ, tu, tv;

		int index, index1, index2, index3, index4;
		// Determine the size of each quad on the sky plane.
		quadSize = planeWidth / (float)planeSize;

		// Calculate the radius of the sky plane based on the width.
		radius = planeWidth / 2.0f;

		// Calculate the height constant to increment by.
		constant = (planeTop - planeBottom) / (radius * radius);

		// Calculate the texture coordinate increment value.
		textureDelta = (float)texRepeat / (float)planeSize;

		// Loop through the sky plane and build the coordinates based on the increment values given.
		for (int j = 0; j <= planeSize; j++)
		{
			for (int i = 0; i <= planeSize; i++)
			{
				// Calculate the vertex coordinates.
				positionX = (-0.5f * planeWidth) + ((float)i * quadSize);
				positionZ = (-0.5f * planeWidth) + ((float)j * quadSize);
				positionY = planeTop - (constant * ((positionX * positionX) + (positionZ * positionZ)));

				// Calculate the texture coordinates.
				tu = (float)i * textureDelta;
				tv = (float)j * textureDelta;

				// Calculate the index into the sky plane array to add this coordinate.
				index = j * (planeSize + 1) + i;

				// Add the coordinates to the sky plane array.
				mSkyPlane[index].x = positionX;
				mSkyPlane[index].y = positionY;
				mSkyPlane[index].z = positionZ;
				mSkyPlane[index].tu = tu;
				mSkyPlane[index].tv = tv;
			}
		}

		// Create the vertex array.
		std::vector<VertexVT> vertices;
		int verticesCount = (planeSize + 1) * (planeSize + 1) * 6;
		vertices.resize(verticesCount);

		std::vector<UINT32>indices;
		indices.resize(verticesCount);

		index = 0;
		// Load the vertex and index array with the sky plane array data.
		for (int j = 0; j < planeSize; j++)
		{
			for (int i = 0; i < planeSize; i++)
			{
				index1 = j * (planeSize + 1) + i;
				index2 = j * (planeSize + 1) + (i + 1);
				index3 = (j + 1) * (planeSize + 1) + i;
				index4 = (j + 1) * (planeSize + 1) + (i + 1);

				// Triangle 1 - Upper Left
				vertices[index].position = CPoint3F(mSkyPlane[index1].x, mSkyPlane[index1].y, mSkyPlane[index1].z);
				vertices[index].texture = CPoint2F(mSkyPlane[index1].tu, mSkyPlane[index1].tv);
				indices[index] = index;
				index++;

				// Triangle 1 - Upper Right
				vertices[index].position = CPoint3F(mSkyPlane[index2].x, mSkyPlane[index2].y, mSkyPlane[index2].z);
				vertices[index].texture = CPoint2F(mSkyPlane[index2].tu, mSkyPlane[index2].tv);
				indices[index] = index;
				index++;

				// Triangle 1 - Bottom Left
				vertices[index].position = CPoint3F(mSkyPlane[index3].x, mSkyPlane[index3].y, mSkyPlane[index3].z);
				vertices[index].texture = CPoint2F(mSkyPlane[index3].tu, mSkyPlane[index3].tv);
				indices[index] = index;
				index++;

				// Triangle 2 - Bottom Left
				vertices[index].position = CPoint3F(mSkyPlane[index3].x, mSkyPlane[index3].y, mSkyPlane[index3].z);
				vertices[index].texture = CPoint2F(mSkyPlane[index3].tu, mSkyPlane[index3].tv);
				indices[index] = index;
				index++;

				// Triangle 2 - Upper Right
				vertices[index].position = CPoint3F(mSkyPlane[index2].x, mSkyPlane[index2].y, mSkyPlane[index2].z);
				vertices[index].texture = CPoint2F(mSkyPlane[index2].tu, mSkyPlane[index2].tv);
				indices[index] = index;
				index++;

				// Triangle 2 - Bottom Right
				vertices[index].position = CPoint3F(mSkyPlane[index4].x, mSkyPlane[index4].y, mSkyPlane[index4].z);
				vertices[index].texture = CPoint2F(mSkyPlane[index4].tu, mSkyPlane[index4].tv);
				indices[index] = index;
				index++;
			}
		}

		CResourceBase* pResource = CResourceManager::getSinglePtr()->createResource(Mesh);
		CMesh* pMesh = dynamic_cast<CMesh*>(pResource);
		CMeshUnit* pMeshUnit = new CMeshUnit;
		pMesh->fillVertexBuffer(&vertices[0], sizeof(VertexVT) * vertices.size(), sizeof(VertexVT));
		pMesh->fillIndexBuffer(&indices[0], sizeof(UINT32)*indices.size(), sizeof(UINT32));
		pMeshUnit->bindMesh(pMesh);
		pMeshUnit->getBoundBox().hide();

		CMaterialUnit* pMaterialUnit = new CMaterialUnit;
		pMaterialUnit->setUnitFile("Resource/Material/skyCloudMaterial.ma");
		pMaterialUnit->onInitialise();
		pMeshUnit->bindMaterial(pMaterialUnit);
		SafeRelease(pMaterialUnit);

		mpMeshUnits.push_back(pMeshUnit);
		mpUnits.push_back(pMeshUnit);

		SafeRelease(pMesh);
		CRenderNode* pRenderNode = GEngine->createRenderNode();
		pRenderNode->bindActor(this, RendererType::FrontRenderer);
		pRenderNode->setRenderLayer(100);
		GEngine->getCurrentScene()->addRenderNode(pRenderNode);
		SafeRelease(pRenderNode);
		disablePick();
		m_brightness = 0.65f;
		m_translationSpeed[0] = 0.0003f;
		m_translationSpeed[1] = 0.0f;
		m_translationSpeed[2] = 0.00015f;
		m_translationSpeed[3] = 0.0;
		return true;
	}

}

